<?php
namespace app\service;

use app\model\MemberModel;
use support\Redis as RedisCache;
use const support\MEMBER_UUID_LEN;
use const support\MEMBER_UUID_SPARE_POOLS;
use const support\MEMBER_UUID_SPARE_POOLS_MAX_LEN;
use const support\MEMBER_UUID_SPARE_POOLS_MIN_LEN;
use const support\MEMBER_UUID_TEST_LEN;
use const support\VERSIONS_PRO;

class UUIDService{

    //缓存标识
    public static function getSparePoolsCacheName(): string
    {
        return sprintf(MEMBER_UUID_SPARE_POOLS,env('VERSIONS',VERSIONS_PRO));
    }

    //获取UUID
    public static function getUUID(): string
    {
        $len=RedisCache::sCard(self::getSparePoolsCacheName());
        if ($len<MEMBER_UUID_SPARE_POOLS_MIN_LEN){
            self::setUUID(MEMBER_UUID_SPARE_POOLS_MIN_LEN);
        }
        $uuid=RedisCache::sPop(self::getSparePoolsCacheName());
        return (string)$uuid;
    }

    //设置UUID
    public static function setUUID(int $maxRepairNum=0): bool
    {
        //已设置数量则生成指定数量，未设置则生成填补量
        if (!$maxRepairNum){
            $len=RedisCache::sCard(self::getSparePoolsCacheName());
            $maxRepairNum=MEMBER_UUID_SPARE_POOLS_MAX_LEN-$len;
        }
        //溢出4分之一作为已存在过滤
        $overflow=(int)floor($maxRepairNum*0.25)?:0;
        $maxRepairNum+=$overflow;
        //新增UUID池
        $uuids=[];
        for ($i=0;$i<$maxRepairNum;$i++){
            //生成指定位数值,测试环境和正式预发生成的长度不一致
            $uuid=rand_string(checkTestEnv()?MEMBER_UUID_TEST_LEN:MEMBER_UUID_LEN,'0123456789');
            $firstDigit = substr($uuid, 0, 1); // 获取第一位数字
            if ($firstDigit  && !in_array($uuid,$uuids)){
                $uuids[]=$uuid;
            }
        }
        //进行连表查询已使用
        $usedMemberIds=MemberModel::whereIn('member_sn',$uuids)->pluck('member_sn')->toArray()?:[];
        //进行差异化剔除
        $diffUuids=array_diff($uuids,$usedMemberIds);
        //数据入池
        RedisCache::pipeline(function ($pipe) use($diffUuids) {
            foreach ($diffUuids as $diffUuid){
                $pipe->sAdd(self::getSparePoolsCacheName(),$diffUuid);
            }
        });
        return true;
    }



}